/**
 * html5 storage
 */
const objType = val => Object.prototype.toString.call(val);

export default class WebStorage {
    
    constructor(storage) {
        if (storage !== 'localStorage' && storage !== 'sessionStorage') {
            storage = 'localStorage';
        }
        this.storage = window[storage];
    }
    
    storage;
    // json格式转换
    jsonFormat = {
        toString(data) {
            return JSON.stringify(data);
        },
        toJson(data) {
            try {
                return JSON.parse(data);
            } catch (err) {
                return data;
            }
        },
    };
    
    // 0为不会过期
    _maxExpire = 0;
    
    // 检查是否为Date类型
    _isValidDate(date) {
        return objType(date) === '[object Date]' && !isNaN(date.getTime());
    }
    
    _msMap = {
        second: 1000,
        hour: 3600000,
        day: 86400000,
        month: 2592000000,
    };
    
    /**
     * 获取过期时间
     * @param opt 的key => date; second,hour,day,month: 值为number
     * @returns {*}
     * @private
     */
    _getExpiresTime(opt) {
        if (!opt || objType(opt) !== '[object Object]') {
            return this._maxExpire;
        }
        try {
            if (opt.date) {
                let expires = new Date(opt.date);
                return this._isValidDate(expires) ? expires.getTime() : this._maxExpire;
            }
            for (let k in opt) {
                if (this._msMap[k]) {
                    let time = Number(opt[k]);
                    if (isNaN(time) || time <= 0 || time === Infinity) {
                        continue;
                    }
                    return Date.now() + time * this._msMap[k];
                }
            }
            return this._maxExpire;
        } catch (e) {
            return this._maxExpire;
        }
    }
    
    // 格式化缓存数据
    _getCacheItem(value, exp) {
        let expires = this._getExpiresTime(exp);
        return {
            e: expires,
            v: value,
        };
    }
    
    // 检查缓存数据格式
    _isCacheItem(cacheItem) {
        if (objType(cacheItem) !== '[object Object]') {
            return false;
        }
        return Reflect.has(cacheItem, 'e') && Reflect.has(cacheItem, 'v');
    }
    
    // 获取key
    _getKey(key) {
        return typeof key === 'string' ? key : JSON.stringify(key);
    }
    
    // 检查是否可用 0不符合格式的, 1有效, 2过期
    _checkEffective(cacheItem) {
        if (!this._isCacheItem(cacheItem)) {
            return 0;
        }
        if (cacheItem.e === 0 || Date.now() < cacheItem.e) {
            return 1;
        }
        return 2;
    }
    
    /**
     * 添加/修改缓存数据
     * @param key
     * @param val
     * @param option
     * @returns {*}
     */
    set(key, val, option) {
        key = this._getKey(key);
        if (typeof val === 'undefined') {
            return this.del(key);
        }
        const cacheItem = this._getCacheItem(val, option);
        try {
            this.storage.setItem(key, this.jsonFormat.toString(cacheItem));
            return key;
        } catch (err) {
            console.error(err);
        }
    }
    
    /**
     * 获取缓存数据
     * @param key
     * @returns {*}
     */
    get(key) {
        key = this._getKey(key);
        const cacheItem = this.jsonFormat.toJson(this.storage.getItem(key));
        const effectiveRst = this._checkEffective(cacheItem);
        if(effectiveRst === 0){
            return cacheItem;
        }
        if(effectiveRst === 1){
            return cacheItem.v;
        }
        this.storage.removeItem(key);
        return null;
    }
    
    /**
     * 删除缓存数据
     * @param key
     * @returns {*}
     */
    del(key) {
        key = this._getKey(key);
        this.storage.removeItem(key);
        return key;
    }
    
    /**
     * 清空所有过期的缓存数据
     * @returns {Array}
     */
    clearExpires() {
        const length = this.storage.length;
        let deleteKeys = [];
        for (let i = 0; i < length; i++) {
            const key = this.storage.key(i);
            const cacheItem = this.jsonFormat.toJson(this.storage.getItem(key));
            if (this._checkEffective(cacheItem) === 2) {
                deleteKeys.push(key);
                this.storage.removeItem(key);
            }
        }
        return deleteKeys;
    }
    
    /**
     * 清空所有缓存数据
     */
    clear() {
        this.storage.clear();
    }
}

export const storageLocal = new WebStorage();
export const storageSession = new WebStorage('sessionStorage');
